﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Text.RegularExpressions;

namespace NinjaParser
{
	public class Program
	{
		static void Main(string[] args)
		{
			while (true)
			{
				string input = Console.ReadLine();
				LinkedList<string> ret = null;

				Console.ForegroundColor = ConsoleColor.Cyan;
				Console.Write("Input: ");
				Console.ForegroundColor = ConsoleColor.White;
				Console.WriteLine(input);
				Console.WriteLine();

				#region First step, tokenize into strings.
				try
				{
					StringTokenizer st = new StringTokenizer(input);
					ret = st.Parse();


					foreach (string token in ret)
					{
						Console.ForegroundColor = ConsoleColor.Green;
						Console.Write("\tToken: ");
						Console.ForegroundColor = ConsoleColor.White;
						Console.WriteLine(token);
					}
				}
				catch (Exception ex)
				{
					Console.ForegroundColor = ConsoleColor.Red;
					Console.WriteLine("Error: " + ex.Message);
					Console.WriteLine();
				}

				#endregion

				#region Second step, build Nodes

				if (ret == null || ret.Count == 0)
				{
					Console.ForegroundColor = ConsoleColor.Red;
					Console.Write("Empty command line.");
					continue;
				}

				CommandNode rootNode;
				
				// First one is command node.
				rootNode = new CommandNode(ret.ElementAt(0));

				if(ret.Count == 1)
					goto finish;
					 

				// Search for prepositions.
				int prepositionIndex = -1;

				for (int i = 1; i < ret.Count; i++)
				{
					if (MatchPreposition(ret.ElementAt(i)))
					{
						prepositionIndex = i;
						break;
					}
				}

				if (prepositionIndex > -1)
				{
					// append all values between Verb and Preposition
					rootNode.ArgumentList = ProcessArguments(ret, 1, prepositionIndex -1);
					rootNode.Preposition = new PrepositionNode(ret.ElementAt(prepositionIndex));


					if (prepositionIndex < ret.Count - 2)
						throw new Exception("More than one argument at target!");
					else
						rootNode.Target = new ArgumentNode(ret.ElementAt(ret.Count - 1));

				}
				else
				{
					// append all values between Verb and EOL
					rootNode.ArgumentList = ProcessArguments(ret, 1, ret.Count - 1);
					rootNode.Preposition = null;
				}


				#endregion



				finish:
				;



			}
		}

		/// <summary>
		/// Processa uma lista de strings e vírgulas. Adiciona as strings individualmente, até uma vírgula
		/// </summary>
		/// <param name="list"></param>
		/// <param name="startOffset"></param>
		/// <param name="endOffset"></param>
		/// <returns></returns>
		private static ArgumentList ProcessArguments(LinkedList<string> list, int startOffset, int endOffset)
		{
			ArgumentList ret = new ArgumentList();
			StringBuilder builder = new StringBuilder();
			bool outside = true;

			for (int i = startOffset; i <= endOffset; i++ )
			{
				string token = list.ElementAt(i);

				// Caso parvo: ", xxxx"
				if (outside && token == ",")
					continue;
				else if (!outside && token == ",")
				{
					// push do builder como um "node". Reset do builder e estado.
					ret.Children.AddLast(new ArgumentNode(builder.ToString().Trim()));
					builder = new StringBuilder();
					outside = true;
				}
				else
				{
					outside = false;
					builder.Append(token);
					builder.Append(" ");
				}
			}

			if(!outside)
				ret.Children.AddLast(new ArgumentNode(builder.ToString().Trim()));
			

			return ret;
		}

		private static bool MatchPreposition(string target)
		{
			foreach (PrepositionType pt in Enum.GetValues(typeof(PrepositionType)))
			{
				if (pt.ToString().ToLower() == target.ToLower())
					return true;
			}

			return false;
		}
	}
}



public enum PrepositionType
{
	To,
	For,
	With
}

public class Node
{
	public string Name { get; set; }
	public Node(string name) { Name = name; }
	public Node() { }
}

public class CommandNode : Node
{
	public CommandNode(string name) : base(name) { }
	public ArgumentList ArgumentList { get; set;}
	public ArgumentNode Target { get; set; }
	public PrepositionNode Preposition { get; set; }

	public override string ToString()
	{
		return Name;
	}

}

public class PrepositionNode : Node
{
	public PrepositionType Type { private set; get; }

	public PrepositionNode(PrepositionType type)
	{
		Type = type;
	}

	public PrepositionNode(string preposition)
	{
		Type = (PrepositionType) Enum.Parse(typeof(PrepositionType), preposition, true);
	}

	public override string ToString()
	{
		return Type.ToString();
	}
}

public class ArgumentNode : Node
{
	public ArgumentNode(string name)
	{
		Name = name;
	}

	public override string ToString()
	{
		return Name;
	}
}

public class ArgumentList : Node
{
	public LinkedList<ArgumentNode> Children { private set; get; }

	public ArgumentList()
	{
		Children = new LinkedList<ArgumentNode>();
	}

}


/*
 * Action
 * Action Direction
 * Action ObjectList
 * Action ObjectList Preposition Object
 * Object
 * Quantifier
 */


/*
 * 
 * look
 * look left
 * open door
 * open all doors
 * open blue door
 * pick blue key, yellow key
 * open left door
 * give blue key to xpto
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 * 
 */
/* Old parser
 * 
 * 
 * CommandLine		:	Command	EOF								{ Commands.Add($1); }
				;

Command 		:	IDENTIFIER								{ $$ = new CommandParsed() { Verb = $1}; }
				|	IDENTIFIER ObjectList					{ $$ = new CommandParsed() { Verb = $1, Nouns = $2	}; }
				|	IDENTIFIER IDENTIFIER '=' IDENTIFIER	{ $$ = new CommandParsed() { Verb = $1, Target = $4}; $$.Nouns.Add($2); }
				|	error									{ $$ = new CommandParsed() { Empty = true} ; }
				;
			
			
ObjectList		:	Object								{ $$.Add($1); }
				|	ObjectList ',' Object				{ $$.Add($3); $$.AddRange($1); }
				;
				
Object			:	MultiPart							{ $$ = new Noun($1); }
				;
				
MultiPart		:	IDENTIFIER							{ $$ = $1; }
				|	MultiPart IDENTIFIER				{ $$ = $1 + " " + $2; }
 
 * 
 * * 
 */


